(function() {
	/*
	 * The following "Proto" code was originally 
	 * developed by Dean Edwards for his Base library.
	 * http://dean.edwards.name/weblog/2006/03/base/
	 * 
	 * Slight modifications to the original code were made:
	 *      - Renamed Base to Proto
	 *      - No longer excepts a second param for statics
	 *      - Statics are now defined in the class definition using the 'statics' property
	 *      - Removed static initializer (init method)
	 */
	// TODO: The following "Proto" (Base) code needs to be rewritten to be smaller, more concise, and to require inheriting through gaf.define only.
	var Proto = function() {
		// Empty on purpose
	}
	Proto.extend = function(instance) { // subclass
	    var extend = Proto.prototype.extend, statics = {};
	    
		// If we defined some statics, remove them
		if ( instance['statics'] ) {
			statics = instance['statics'];
			delete instance['statics'];
		}
	    // build the prototype
	    Proto._prototyping = true;
	    var proto = new this;
	    extend.call(proto, instance);
	    proto.base = function(){
	        // call this method from any other method to invoke that method's ancestor
	    };
	    delete Proto._prototyping;
	    
	    // create the wrapper for the constructor function
	    //var constructor = proto.constructor.valueOf(); //-dean
	    var constructor = proto.constructor;
	    var klass = proto.constructor = function(){
	        if ( !Proto._prototyping ) {
	            if (this._constructing || this.constructor == klass) { // instantiation
					this._constructing = true;
					constructor.apply(this, arguments);
					delete this._constructing;
				}
				else {
					if (arguments[0] != null) { // casting
						return (arguments[0].extend || extend).call(arguments[0], proto);
					}
				}
	        }
	    };
	    
	    // build the class interface
	    klass.ancestor = this;
	    klass.extend = this.extend;
	    klass.prototype = proto;
	    klass.toString = this.toString;
	    klass.valueOf = function(type){
	        return (type == "object") ? klass : constructor.valueOf();
	    };
	    extend.call(klass, statics);
	    return klass;
	};
	Proto.prototype = {
	    extend: function(source, value){
	        if (arguments.length > 1) { // extending with a name/value pair
				var ancestor = this[source];
				if (ancestor && (typeof value == "function") && (!ancestor.valueOf || ancestor.valueOf() != value.valueOf()) && /\bbase\b/.test(value)) {
					// get the underlying method
					var method = value.valueOf();
					// override
					value = function(){
						var previous = this.base || Proto.prototype.base;
						this.base = ancestor;
						var returnValue = method.apply(this, arguments);
						this.base = previous;
						return returnValue;
					};
					// point to the underlying method
					value.valueOf = function(type){
						return (type == "object") ? value : method;
					};
					value.toString = Proto.toString;
				}
				this[source] = value;
			}
			else {
				if (source) { // extending with an object literal
					var extend = Proto.prototype.extend;
					// if this object has a customised extend method then use it
					if (!Proto._prototyping && typeof this != "function") {
						extend = this.extend || extend;
					}
					var proto = {
						toSource: null
					};
					// do the "toString" and other methods manually
					var hidden = ["constructor", "toString", "valueOf"];
					// if we are prototyping then include the constructor
					var i = Proto._prototyping ? 0 : 1;
					while (key = hidden[i++]) {
						if (source[key] != proto[key]) {
							extend.call(this, key, source[key]);
						}
					}
					// copy each of the source object's properties to this object
					for (var key in source) {
						if (!proto[key]) {
							extend.call(this, key, source[key]);
						}
					}
				}
			}
	        return this;
	    }
	};
	Proto = Proto.extend({
	    constructor: function(){
	        this.extend(arguments[0]);
	    },
		destroy: function() {
			// TODO: Clean up any used resources
		}
	}, {
	    ancestor: Object,
	    version: "1.1",
		
	    toString: function(){
	        return String(this.valueOf());
	    }
	});
    /* -------------------------
	 * 	Private Methods
	 * ------------------------- */
	// TODO: Make private
	gaf._createObjects = function(namespace, nsOnly) {
		// Create our namespaces
		var ns = window;
		
		if ( typeof namespace == 'string' && namespace !== '') {
			var spaces = namespace.split('.');
			for ( var i = 0; i <= spaces.length - 1; i++ ) {
				if ( !ns[spaces[i]] ) {
					if ( i == spaces.length - 1 && nsOnly ) {
						break;
					}
					else {
						ns[spaces[i]] = {};
					}
				} else {
					if ( i == spaces.length - 1 && nsOnly ) {
						break;
					}
				}
				ns = ns[spaces[i]];
			}
		}
		
		return ns;
	};
    /* -------------------------
	 * 	Public Methods
	 * ------------------------- */
	// TODO: Refactor this method to make it more concise
	gaf.extend = function(instance, superClass) {
		var newObject;
		if ( !superClass.extend ) {
			if ( typeof superClass == 'function' ) {
				superClass = Proto.extend(superClass);
				newObject = superClass.extend(instance);
			} else {
				// We don't have a function, do just a normal copy (implement)
				newObject = gaf.implement(instance, superClass);
			}
		} else {
			newObject = superClass.extend(instance);
		}
		
		return newObject;
	};
	gaf.implement = function(target, source) {
		var newSource = source;
		// If we're a function create a new instance for copying
		if ( typeof newSource == 'function' ) {
			newSource = new source;
		}
		
		var name, x;
		for ( name in newSource ) {
			x = newSource[name];
			// Note that if the source item exists in the target it won't be overwritten
			if ( !(name in target) || target[name] !== x ) {
				target[name] = x;
			}
		}
		
		delete newSource;
		return target;
	};
	// TODO: Refactor this method to make it more concise
	gaf.define = function(name, superClass, obj) {
		var newObject;
			
		if (name != null) {
			// Get our object name
			var newName = name.split('.');
			newName = newName[newName.length - 1];
			// Create our namespace, leaving the object out
			var ns = gaf._createObjects(name, true);
			// If we already exist disallow creation
			if ( ns[newName] ) {
				throw new Error('The class definition "' + name + '" already exists! Use gaf.define, gaf.extend, or ' + name + '.extend to extend the ' + name + ' class.');
			}
		} else {
			obj = {
				statics: obj
			};
		}
		
		if (superClass) {
			if (typeof superClass == 'object' || typeof superClass == 'function') {
				newObject = gaf.extend(obj, superClass);
			} else {
				throw new Error('You can only inherit from objects and functions!');
			}
		}
		else {
			newObject = Proto.extend(obj);
		}
		
		if ( name != null ) {
			ns[newName] = newObject;
		}
		return newObject;
	};
})();
